package com.been.common.dao.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.SQLException;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.criterion.Example;
import org.springframework.orm.hibernate3.HibernateCallback;

import static com.been.common.constants.StringContants.COMMA_STRING;

import com.been.common.dao.GenericDAO;
import com.been.common.model.BaseModel;
import com.been.common.page.PageInfo;

/**
 * 泛型化DAO，所有DAO都应该继承的父类 封装了保存，删除， <br>
 * 按ID查找，按示例对象查找，按单个属性值查找，按多个属性值查找，<br>
 * 查出全部等方法 其他DAO只需继承该类就拥有上诉方法，并且操作指定的model类型
 * 
 * @param <T>
 *            该DAO所操纵的model类型参数
 * @author been
 * 2011-10-01
 */
public class GenericDAOImpl<T extends BaseModel> extends PublicDAOImpl implements GenericDAO<T> {
	
	/**
	 * 类型参数
	 */
	private Class<T> entityClass;
	
	/**
	 * 为实现该类的实体类型名称
	 */
	private String entityName;
	
	/**
	 * 构造方法
	 */
	@SuppressWarnings("unchecked")
	public GenericDAOImpl(){
		Type type = this.getClass().getGenericSuperclass();
		if(type != PublicDAOImpl.class){
			Type trueType = ((ParameterizedType) type).getActualTypeArguments()[0];
			this.entityClass = (Class<T>)trueType;
			this.setEntityName(this.entityClass.getSimpleName());
		}
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.been.common.dao.PublicDAO#findByPage(java.lang.String,
	 * java.lang.Object[], com.been.common.page.PageInfo)
	 */
	@SuppressWarnings("unchecked")
	public List<T> findByPage(final String queryString,
			final Object[] parameters, final PageInfo pageInfo) {
		return (List<T>) this.getHibernateTemplate().execute(
				new HibernateCallback() {
					@Override
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createQuery(queryString);
						if (parameters != null) {
							for (int i = 0; i < parameters.length; i++) {
								query.setParameter(i, parameters[i]);
							}
						}
						ScrollableResults sr = query.scroll();
						sr.last();
						int totalCount = sr.getRowNumber();
						/*if (totalCount == -1) {
						}*/
						int startIndex = (pageInfo.getPageIndex() - 1)
								* pageInfo.getPageSize();
						query.setMaxResults(pageInfo.getPageSize());
						query.setFirstResult(startIndex);
						int totalRec = totalCount + 1;
						pageInfo.setTotalRec(totalRec);
						int totalPage = (totalRec % pageInfo.getPageSize() == 0) ? (totalRec / pageInfo
								.getPageSize()) : (totalRec / pageInfo
								.getPageSize()) + 1;
						int[] pageNumbers = new int[totalPage];
						for (int i = 0; i < totalPage; i++) {
							pageNumbers[i] = (i + 1);
						}
						pageInfo.setPageNumbers(pageNumbers);
						pageInfo.setTotalPage(totalPage);
						pageInfo.setPageSize(pageInfo.getPageSize());
						int pageIndex = pageInfo.getPageIndex();
						pageInfo.setPageIndex(pageIndex);
						pageInfo.setPrevPage(pageIndex - 1);
						pageInfo.setNextPage(pageIndex + 1);
						pageInfo.setHasNextPage(pageIndex < totalPage);
						pageInfo.setHasPrevPage(pageIndex > 1);
						pageInfo.setHasPageInfo(totalRec>0);
						return query.list();
					}
				});
	}

	/* (non-Javadoc)
	 * @see com.been.common.dao.PublicDAO#findByQuery(java.lang.String, java.lang.Object[])
	 */
	@SuppressWarnings("unchecked")
	public List<T> findByQuery(final String queryString,final Object[] parameters) {
		return (List<T>)this.getHibernateTemplate().execute(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {
				Query query = session.createQuery(queryString);
				if(parameters !=null){
					for(int i=0;i<parameters.length;i++){
						query.setParameter(i, parameters[i]);
					}
				}
				return query.list();
			}
		});
	}
	
	/**
	 * 设置实体类型名称
	 * @param entityName 实体类型名称
	 */
	public void setEntityName(String entityName) {
		this.entityName = entityName;
	}

	/* (non-Javadoc)
	 * @see com.been.common.dao.GenericDAO#findById(java.io.Serializable)
	 */
	@SuppressWarnings("unchecked")
	public T findById(Serializable id) {
		return (T)this.getHibernateTemplate().get(this.entityClass, id);
	}

	/* (non-Javadoc)
	 * @see com.been.common.dao.GenericDAO#deleteByIds(java.lang.String)
	 */
	public int deleteByIds(String ids) {
		if(ids.endsWith(COMMA_STRING)){
			ids = ids.substring(0,ids.length()-1);
		}
		String hql = " delete from "+this.entityName+" model where model in("+ids+")";
		return this.createQuery(hql).executeUpdate();
	}

	/* (non-Javadoc)
	 * @see com.been.common.dao.GenericDAO#findByExample(com.been.common.model.BaseModel)
	 */
	@SuppressWarnings("unchecked")
	public List<T> findByExample(T instance) {
		return this.getSession().createCriteria(entityClass).add(Example.create(instance)).list();
	}
}
